package com.dp.appi.util.wxpay;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.StringUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.Reader;
import java.io.StringReader;
import java.util.*;

/**
 * Created by chenghao on 2015/8/20.
 */
public class WxUtil {

    //商户密钥
    public static String API_KEY = "xialipengdeshejitong013709083412";
    //公众号appid
    public static String APP_ID = "wxa9dce63dbcbe06b2";
    //商户号id
    public static String MCH_ID = "1387968102";


    public static String toXml(List<NameValuePair> params) {
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        for (int i = 0; i < params.size(); i++) {
            sb.append("<" + params.get(i).getName() + ">");
            sb.append(params.get(i).getValue());
            sb.append("</" + params.get(i).getName() + ">");
        }
        sb.append("</xml>");
        return sb.toString();
    }

    public static Map<String, String> decodeXml(String content) {
        try {
            Map<String, String> xml = new HashMap<>();
            SAXReader reader = new SAXReader();
            Reader r = new StringReader(content);
            Document document = reader.read(r);
            Element root = document.getRootElement();
            // 得到根元素的所有子节点
            List<Element> elementList = root.elements();

            // 遍历所有子节点
            for (Element e : elementList) {
                xml.put(e.getName(), e.getText());
            }

            return xml;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String genPackageSign(List<NameValuePair> params) {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < params.size(); i++) {
            sb.append(params.get(i).getName());
            sb.append('=');
            sb.append(params.get(i).getValue());
            sb.append('&');
        }
        sb.append("key=");
        sb.append(API_KEY);

        String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
        return packageSign;
    }

    /**
     * 获取微信预支付交易会话ID
     */
    public static Map<String, String> unifiedOrder(String totalFee, String spbillCreateIp, String outTradeNo, String body, String wx_notify_url, String attach) {
        String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
        String entity = genProductArgs(totalFee, spbillCreateIp, outTradeNo, body, wx_notify_url, attach);
        byte[] buf = Util.httpPost(url, entity);
        String content = new String(buf);
        Map<String, String> map = decodeXml(content);

        Map<String, String> result = null;
        String return_code = map.get("return_code");//=SUCCESS通信成功
        String return_msg = map.get("return_msg");//=OK签名成功
        String result_code = map.get("result_code");//=SUCCESS交易成功
        if ("SUCCESS".equals(return_code) && "OK".equals(return_msg) && "SUCCESS".equals(result_code)) {
            result = new HashMap<>();
            result.put("appid", APP_ID);
            result.put("partnerid", MCH_ID);
            result.put("prepayid", map.get("prepay_id"));
            result.put("noncestr", map.get("nonce_str"));
            result.put("package", "Sign=WXPay");
            result.put("timestamp", String.valueOf(genTimeStamp()));

            List<NameValuePair> signParams = new LinkedList<>();
            signParams.add(new BasicNameValuePair("appid", result.get("appid")));
            signParams.add(new BasicNameValuePair("noncestr", result.get("noncestr")));
            signParams.add(new BasicNameValuePair("package", result.get("package")));
            signParams.add(new BasicNameValuePair("partnerid", result.get("partnerid")));
            signParams.add(new BasicNameValuePair("prepayid", result.get("prepayid")));
            signParams.add(new BasicNameValuePair("timestamp", result.get("timestamp")));
            String sign = genPackageSign(signParams);
            result.put("sign", sign);
        }

        return result;
    }

    private static String genProductArgs(String totalFee, String spbillCreateIp, String outTradeNo, String body, String wx_notify_url, String attach) {
        try {
            List<NameValuePair> packageParams = new LinkedList<>();
            packageParams.add(new BasicNameValuePair("appid", APP_ID));
            packageParams.add(new BasicNameValuePair("attach", attach));
            packageParams.add(new BasicNameValuePair("body", body));
            packageParams.add(new BasicNameValuePair("mch_id", MCH_ID));
            packageParams.add(new BasicNameValuePair("nonce_str", genNonceStr()));
            packageParams.add(new BasicNameValuePair("notify_url", wx_notify_url));
            packageParams.add(new BasicNameValuePair("out_trade_no", outTradeNo));
            packageParams.add(new BasicNameValuePair("spbill_create_ip", spbillCreateIp));
            packageParams.add(new BasicNameValuePair("total_fee", totalFee));
            packageParams.add(new BasicNameValuePair("trade_type", "APP"));
            String sign = genPackageSign(packageParams);
            packageParams.add(new BasicNameValuePair("sign", sign));

            String xmlstring = toXml(packageParams);

            return  new String(xmlstring.toString().getBytes());
        } catch (Exception e) {
            return null;
        }
    }

    private static String genNonceStr() {
        Random random = new Random();
        return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
    }

    private static long genTimeStamp() {
        return System.currentTimeMillis() / 1000;
    }


    /**
     * 获取微信回调时的参数
     *
     * @param request
     * @return
     */
    public static Map<String, String> getWxResult(HttpServletRequest request) {
        Map<String, String> xml = new HashMap<>();
        try {
            ServletInputStream in = request.getInputStream();

            SAXReader reader = new SAXReader();
            Document document = reader.read(in);
            Element root = document.getRootElement();
            // 得到根元素的所有子节点
            List<Element> elementList = root.elements();
            for (Element e : elementList) {
                xml.put(e.getName(), e.getText());
            }

            //签名微信返回数据，除了key为sign外
            //如果签名的结果值等于了微信返回的sign值时就说明成功
            String callbackParamSign = getCallbackSign(xml);
            xml.put("callbackParamSign", callbackParamSign);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            return xml;
        }
    }
    public static String getCallbackSign(Map<String, String> param){
        Map<String, String> map = new HashMap<>();

        Set<String> keys = param.keySet();
        for(String key : keys){
            //key为sign，且值为空时不进行签名
            if(key != "sign" && !StringUtils.isEmpty(param.get(key))){
                map.put(key, param.get(key));
            }
        }

        Object[] key = map.keySet().toArray();
        Arrays.sort(key);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < key.length; i++) {
            sb.append(key[i]);
            sb.append('=');
            sb.append(map.get(key[i]));
            sb.append('&');
        }
        sb.append("key=");
        sb.append(API_KEY);
        String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();

        return packageSign;
    }
}

